#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>


template <class T>
class BlockQueue
{
    static const int defaultNum=20;
private:
    std::queue<T>_q;
    int _maxsize;
    pthread_mutex_t _mutex;
    pthread_cond_t c_cond;
    pthread_cond_t p_cond;
    int low_water;
    int high_water;

public:
    BlockQueue(int maxcap=defaultNum)
        :_maxsize(maxcap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&c_cond,nullptr);
        pthread_cond_init(&p_cond,nullptr);
        low_water=_maxsize/3;
        high_water=_maxsize*2/3;
    }

    void push(const T &in)
    {
        pthread_mutex_lock(&_mutex);
        while(_q.size()==_maxsize)// 判断也是访问临界资源，因此必须要有锁;因为存在伪唤醒的状况，因此需要一直判断
        {
            pthread_cond_wait(&p_cond,&_mutex);// 线程在等待的时候会自动释放锁，返回函数的时候会重新持有锁
        }
        _q.push(in);
        if(_q.size()>high_water)
            pthread_cond_signal(&c_cond);
        pthread_mutex_unlock(&_mutex);
    }

    T pop()
    {
        pthread_mutex_lock(&_mutex);
        while(_q.size()==0)
        {
            pthread_cond_wait(&c_cond,&_mutex);
        }
        T out=_q.front();
        _q.pop();
        if(_q.size()<low_water)
            pthread_cond_signal(&p_cond);
        pthread_mutex_unlock(&_mutex);
        return out;
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&c_cond);
        pthread_cond_destroy(&p_cond);
    }
};